In [69]:
from matplotlib import rcParams
%matplotlib inline
import pandas as pd
import scanpy as sc
from matplotlib import rcParams
import numpy as np

import scfate as scr
from scfate.genome.sequences import *
from scfate.motifs.score import *
from scfate.genome.FastaAnalyzer import FastaAnalyzer
from lib.HumanTFs import HumanTFs
from sklearn.metrics import roc_auc_score

import warnings
warnings.filterwarnings("ignore")

%matplotlib inline
In [422]:
def set_figsize(w, h):
    rcParams['figure.figsize'] = w, h
def set_figdpi(dpi):
    rcParams['figure.dpi'] = dpi
In [197]:
adata = sc.read('/mnt/znas/icb_zstore01/groups/ml01/workspace/ignacio.ibarra/theislab/retinal_scRNAseq_integration/data/integrated/integration_scgen_unscaled_hvg.h5ad')
In [198]:
adata.obs
Out[198]:
batch cell.type leiden n_counts study tech cell.id
0 0 Rod 3 1018.0 hafler 10x AAACCCAGTGGAACAC-100000000000
1 0 AC 8 1369.0 hafler 10x AAACGAAAGAGAGGTA-100000000000
2 0 NN 5 4049.0 hafler 10x AAACGAACAGGTTTAC-100000000000
3 0 BC 1 1803.0 hafler 10x AAACGCTCAATGTCTG-100000000000
4 0 NN 5 3823.0 hafler 10x AAACGCTTCGCTTGCT-100000000000
... ... ... ... ... ... ... ...
32817 1 BC 0 NaN scheetz 10x TTTGATCCAACCGGAA-11
32818 1 NN 2 NaN scheetz 10x TTTGGAGGTGCGAACA-11
32819 1 UN 4 NaN scheetz 10x TTTGGAGTCCGACAGC-11
32820 1 UN 4 NaN scheetz 10x TTTGGTTTCCACGGAC-11
32821 1 UN 4 NaN scheetz 10x TTTGTTGAGCTAAACA-11

32822 rows × 7 columns

In [319]:
set_figsize(10, 5)
sc.pl.umap(adata, color=['cell.type', 'leiden'], ncols=2)
In [201]:
adata
Out[201]:
AnnData object with n_obs × n_vars = 32822 × 2000
    obs: 'batch', 'cell.type', 'leiden', 'n_counts', 'study', 'tech', 'cell.id'
    uns: 'cell.type_colors', 'neighbors', 'study_colors', 'umap', 'leiden_colors'
    obsm: 'X_umap', 'latent'
    obsp: 'connectivities', 'distances'
In [202]:
species = 'human'
archetypes_path = 'data/%s_tss_2000_archetypes_hits_top5_mean_scaled.tsv.gz' % species

import os
os.path.getsize(archetypes_path) / 1e6
Out[202]:
115.535043
In [203]:
!ls -ltrh $archetypes_path
-rw-r--r--. 1 ignacio.ibarra OG-ICB-User 111M Dec  3 02:58 data/human_tss_2000_archetypes_hits_top5_mean_scaled.tsv.gz
In [204]:
archetypes = pd.read_csv(archetypes_path, sep='\t', compression='gzip', index_col=0)
In [205]:
archetypes = archetypes[archetypes.index.isin(set(adata.var.index))]
archetypes.shape
Out[205]:
(1907, 282)
In [206]:
adata = adata[:,adata.var.index.isin(set(archetypes.index))]
adata.shape
Out[206]:
(32822, 1907)
In [207]:
adata.varm['archetypes'] = np.array(archetypes.reindex(adata.var.index))
In [208]:
adata.varm['archetypes']
Out[208]:
array([[-0.39674834, -1.31049758, -0.06966976, ..., -1.56374654,
         0.82111212, -1.13248493],
       [-0.59917593, -0.810411  ,  0.83244022, ..., -0.48916303,
         0.09892936, -1.02118109],
       [-1.11646142, -1.31049758,  0.0696297 , ..., -1.29772405,
         0.51756714, -0.91055352],
       ...,
       [-1.11646142,  0.52192855,  0.57313213, ...,  0.69356115,
         1.12241782, -1.13248493],
       [-0.59917593, -0.62680098,  2.21042499, ..., -1.66876732,
        -0.19848061, -0.36607957],
       [-0.55678272, -1.31049758,  0.71208494, ..., -1.74496195,
         0.27511152, -0.25666418]])
In [209]:
q = 95
qp = q / 100
k ='archetypes.scores.q%i' % q
print(k)
score_archetypes(adata, q=qp, key_obsm=k)
archetypes.scores.q95
WARNING: provided gene list has length 0, scores as 0
WARNING: provided gene list has length 0, scores as 0
In [210]:
adata.shape
Out[210]:
(32822, 1907)
In [211]:
for c in adata.obsm['archetypes.scores.q95']:
    adata.obs['score.archetypes.q95.%i' % (int(c) + 1)] = adata.obsm['archetypes.scores.q95'][c]
In [212]:
key_list = [c for c in adata.obs if 'score.archetypes.q95' in c]
hm = sc.get.obs_df(adata, key_list)

# scale 
hm = (hm - hm.mean(axis=0)) / hm.std(axis=0)
hm
Out[212]:
score.archetypes.q95.1 score.archetypes.q95.2 score.archetypes.q95.3 score.archetypes.q95.4 score.archetypes.q95.5 score.archetypes.q95.6 score.archetypes.q95.7 score.archetypes.q95.8 score.archetypes.q95.9 score.archetypes.q95.10 score.archetypes.q95.11 score.archetypes.q95.12 score.archetypes.q95.13 score.archetypes.q95.14 score.archetypes.q95.15 ... score.archetypes.q95.268 score.archetypes.q95.269 score.archetypes.q95.270 score.archetypes.q95.271 score.archetypes.q95.272 score.archetypes.q95.273 score.archetypes.q95.274 score.archetypes.q95.275 score.archetypes.q95.276 score.archetypes.q95.277 score.archetypes.q95.278 score.archetypes.q95.279 score.archetypes.q95.280 score.archetypes.q95.281 score.archetypes.q95.282
0 0.994432 1.467646 -0.084254 0.424009 0.202249 -0.247187 0.211618 -0.073466 -0.252016 2.015699 0.218455 -1.008066 -0.935631 1.471930 2.554017 ... -0.571402 -2.052811 -0.818944 -0.092745 0.448902 0.883311 1.746637 -0.923515 0.331919 -1.025074 -1.352441 -0.160316 0.116876 -1.381418 -0.000842
1 1.567013 -0.730934 -3.116317 0.181862 0.756052 1.901816 -2.960386 2.481364 0.482735 -2.468939 -0.498331 -1.758137 1.853477 0.070581 0.202831 ... 0.594990 3.618559 2.058404 1.764774 -0.224229 2.154187 0.212680 1.954746 3.051872 -1.064640 -2.715820 0.288697 -0.531373 0.764186 3.398297
2 1.263385 -1.718405 -0.162205 -1.388770 -0.601465 -1.822435 1.013178 0.473094 -1.255286 -0.725031 -0.323730 0.009037 1.090811 1.254978 -0.527977 ... 1.932665 1.165670 0.660069 0.327732 1.160454 0.089141 -1.188163 -0.309047 0.776930 -0.113765 0.455867 -0.629031 -1.645861 1.582447 -0.141649
3 -0.910939 0.614604 -0.054937 -0.815835 -1.564733 1.245385 0.161432 -0.452067 0.968570 -1.387739 2.468641 1.531131 1.253967 1.561293 0.974573 ... 1.433403 2.274492 1.020878 1.970652 -1.769638 0.034036 -0.316090 2.125948 0.231209 1.339233 -1.661711 -0.161523 -1.081602 0.351398 0.298755
4 0.133662 -2.248154 -0.305257 -1.942467 -1.274896 -1.670344 0.409239 1.288433 -0.827283 -1.570663 -0.611539 0.087800 0.858864 0.548238 -1.432899 ... 1.128879 0.971122 0.489269 0.221720 1.041871 -0.193676 -1.015216 -0.578418 0.524709 -0.474728 0.341728 -1.525010 -2.092794 2.266517 -0.609169
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
32817 -0.250206 -0.108956 -1.651283 -1.098089 -0.990799 0.911405 0.142074 0.575665 -0.547735 -0.668793 0.584102 0.249206 -0.214799 0.306865 1.035363 ... -0.217322 0.534808 1.526076 1.241078 -0.215704 0.656337 1.318388 0.471174 0.510469 1.078506 -1.664258 0.271583 -0.299326 0.033748 -1.188245
32818 -0.334186 -1.619692 -0.283158 -1.283104 -0.609508 -1.252974 0.356460 -0.419170 -1.383694 -1.190840 -0.903870 -0.695980 -0.311269 -0.657288 -1.651773 ... 0.620823 0.727492 0.080042 -0.554902 0.249592 -0.397184 -1.269077 -0.892078 0.425438 -0.973533 0.757062 -0.944033 -1.787889 1.276973 -0.695697
32819 1.200910 -0.378716 0.182632 0.729407 -0.485573 -0.459246 0.873682 -1.927784 -1.191518 -0.656825 0.011459 -1.910389 0.761888 0.902781 -0.635718 ... -0.951210 1.614202 0.130478 -0.726430 0.826045 -0.356314 -0.308004 -0.170857 1.224149 0.851331 2.244304 -0.603267 -0.837155 0.223970 -0.570539
32820 1.205387 -0.468823 0.489251 -0.191452 -0.267235 0.122425 -0.739980 -0.709387 -1.673529 -1.158397 0.390973 -1.490646 0.860993 1.274531 -0.853196 ... -1.140777 1.271996 -0.210307 -0.891922 0.615965 -1.128160 -0.731188 -0.861471 0.192248 0.592580 0.817854 -0.711674 -0.723268 0.094751 -0.839050
32821 1.621602 -0.014965 0.272324 1.137609 0.992929 0.598017 1.247247 -2.925298 -1.502920 -0.672379 -0.394441 -2.092068 0.354855 1.749370 -0.395255 ... -2.575152 1.765119 0.061552 -1.887078 1.108668 -1.714076 0.711015 -0.193520 1.098026 0.740651 2.677969 0.666883 0.044409 -0.133346 -0.397325

32822 rows × 282 columns

ROC-AUC by cell types and leiden groups

In [243]:
df = []
for by in ['cell.type', 'leiden']:
    hm[by] = adata.obs[by]
    for s in set(hm[by]):
        print(by, s)
        for ci in hm:
            if not 'score' in ci:
                continue
            fg = hm[hm[by] == s][ci]
            bg = hm[hm[by] != s][ci]

            y_true = np.concatenate([np.repeat(1, len(fg)), np.repeat(0, len(bg))])
            y_score = np.concatenate([fg, bg])

            y_score = np.where(np.isnan(y_score), 0, y_score)

            if sum(y_score) == np.nan:
                continue

            roc_auc = roc_auc_score(y_true, y_score)
            df.append([s, ci, roc_auc, by])
    if by in hm:
        del hm[by]
df = pd.DataFrame(df, columns=['cluster', 'archetype', 'roc.auc', 'by'])
df.head()
cell.type Rod
cell.type RGC
cell.type NN
cell.type AC
cell.type Cone
cell.type BC
cell.type HC
cell.type UN
leiden 6
leiden 7
leiden 9
leiden 8
leiden 3
leiden 2
leiden 11
leiden 5
leiden 14
leiden 13
leiden 0
leiden 12
leiden 10
leiden 4
leiden 1
Out[243]:
cluster archetype roc.auc by
0 Rod score.archetypes.q95.1 0.227184 cell.type
1 Rod score.archetypes.q95.2 0.788103 cell.type
2 Rod score.archetypes.q95.3 0.897114 cell.type
3 Rod score.archetypes.q95.4 0.901941 cell.type
4 Rod score.archetypes.q95.5 0.712352 cell.type
In [245]:
from lib.Archetypes import Archetypes
clu = Archetypes.get_archetypes_clusters(datadir='data')
motif = Archetypes.get_archetypes_motifs(datadir='data')
motif['symbol'] = motif['Motif'].str.split('_').str[0].str.split('.').str[0].str.lower().str.capitalize()


name_by_cluster = clu.set_index('Cluster_ID')['Name'].to_dict()
False data/archetypes/motif_annotations.xlsx
https://resources.altius.org/~jvierstra/projects/motif-clustering/releases/v1.0/motif_annotations.xlsx
In [492]:
def plot_motifs_rows_clustermap(fg_rows, log=False):
    set_figdpi(100)
    set_figsize(5, 10)
    nrow = len(fg_rows)
    pi = 0
    rows_meme = None
    for idx in fg_rows:
        pi += 1
        cluster_name = idx.split(', ')[0]
        cluster_id = list(clu[clu['Name'] == cluster_name]['Cluster_ID'])[0]
        pfm_id = motif[motif['Cluster_ID'] == cluster_id]['Motif']
        
        # print(cluster_id, list(pfm_id))
        pfm_id = list(pfm_id[(pfm_id.str.contains('H11MO') & pfm_id.str.contains('MOUSE')) | (pfm_id.str.contains('_MA'))])
        found = len(pfm_id) != 0
        # print(pi, pfm_id, 'found=%i' % found)

        if found:
            pfm_id = pfm_id[0]
        else:
             pfm_id = list(motif[motif['Cluster_ID'] == cluster_id]['Motif'])[0]
        pfm_path = None
        if log:
            print(pi, pfm_id)
        if '_MA' in pfm_id: # Jaspar
            pfm_path = 'data/JASPAR/%s.jaspar' % pfm_id.split('_')[-1]
            # print(exists(pfm_path), pfm_path)
            rows = [r.strip() for r in open(pfm_path)]
            motif_id = rows[0].split("\t")[0][1:]
            pfm = pd.DataFrame([list(map(int, r.replace("]", "").replace("[", "").split()[1:]))
                               for r in rows[1:]])
            pfm = pfm.T
            pfm.columns = 'A', 'C', 'G', 'T'
            pfm.index += 1
            ppm = pfm.T

        elif 'H11MO' in pfm_id: # hocomoco
            pfm_path = 'data/HOCOMOCOv11/pcm/%s.pcm' % pfm_id

            pfm = pd.read_csv(pfm_path, skiprows=1, sep='\t', header=None)
            # print(exists(pfm_path), pfm_path)
            pfm.columns = ['A', 'C', 'G', 'T']
            ppm = pfm.transpose()
        else: # jaspar
            meme_path = join('data/Taipale_2013/jolma2013.meme')
            rows_meme = [r.strip() for r in open(meme_path)] if rows_meme is None else rows_meme
            start = [ri for ri, r in enumerate(rows_meme) if pfm_id in r][0]
            end = [ri for ri, r in enumerate(rows_meme[start:]) if 'MOTIF' in r][1]
            ppm = [[float(v) for v in p.split(' ') if len(v) != 0] for p in rows_meme[start: start + end][3:-2]]
            ppm = pd.DataFrame(ppm, columns=['A', 'C', 'G', 'T']).transpose()

        # freqs to probs
        for c in ppm:
            col_sum = sum(ppm[c])
            ppm[c] /= col_sum

        ppm.columns = [i for i in range(len(ppm.columns))]
        
        if log:
            print(ppm)
        ax = plt.subplot(nrow + 1, 4, pi * 4 + 4)

        HumanTFs.plot_pwm_model(pfm_id, ppm=ppm, ax=ax)

            
        plt.xlabel('')    
        # Hide the right and top spines
        ax.spines['left'].set_visible(False)
        ax.spines['bottom'].set_visible(False)
        
        ax.yaxis.set_label_position("right")
        ax.yaxis.tick_right()
        plt.ylabel(cluster_name, rotation=0, va='center', ha='left', labelpad=2.0)

        plt.tick_params(left=False, bottom=False, right=False, labelleft=False, labelbottom=False, labelright=False)

    plt.subplots_adjust(bottom=.5)
In [247]:
tfs = pd.read_csv('data/hs/TF_Information_all_motifs_plus.txt', sep='\t')
symbol_by_model = tfs[tfs['TF_Status'] == 'D'].set_index('DBID.1')['TF_Name'].to_dict()

tfs = tfs[~tfs['TF_Name'].isin(motif['symbol']) & (tfs['TF_Status'] == 'I')]
tfs['TF_Name_other'] = tfs['DBID.1'].map(symbol_by_model)
tfs = tfs[~pd.isnull(tfs['TF_Name_other'])]
tfs[tfs['TF_Name'] == 'Neurog3']
print(len(set(tfs['TF_Name'])))
# others_by_query = {ref: {t.split('_')[0].lower().capitalize() for t in grp[grp['TF_Status'] == 'I']['DBID.1']} for ref, grp in tfs.groupby('TF_Name')}
598
In [248]:
motif = Archetypes.get_archetypes_motifs(datadir='data')
motif['symbol'] = motif['Motif'].str.split('_').str[0].str.split('.').str[0].str.lower().str.upper()

others = []
for missing_tf in set(tfs['TF_Name']):
    motif_other = motif[motif['symbol'].isin(tfs[tfs['TF_Name'] == missing_tf]['TF_Name_other'])].drop_duplicates('Cluster_ID').copy()
    motif_other['symbol'] = missing_tf
    others.append(motif_other.drop_duplicates("symbol"))
others = pd.concat(others)
motif = pd.concat([motif, others])
https://resources.altius.org/~jvierstra/projects/motif-clustering/releases/v1.0/motif_annotations.xlsx
In [249]:
def grouped_obs_mean(adata, group_key, layer=None, gene_symbols=None):
    if layer is not None:
        getX = lambda x: x.layers[layer]
    else:
        getX = lambda x: x.X
    if gene_symbols is not None:
        new_idx = adata.var[idx]
    else:
        new_idx = adata.var_names

    grouped = adata.obs.groupby(group_key)
    out = pd.DataFrame(
        np.zeros((adata.shape[1], len(grouped)), dtype=np.float64),
        columns=list(grouped.groups.keys()),
        index=adata.var_names
    )

    for group, idx in grouped.indices.items():
        X = getX(adata[idx])
        out[group] = np.ravel(X.mean(axis=0, dtype=np.float64))
    return out
In [251]:
from matplotlib import rcParams
import matplotlib.pyplot as plt
In [423]:
rcParams['figure.dpi'] = 100
rcParams['figure.figsize'] = [20, 20]
res = []
pi = 0

for by in ['leiden', 'cell.type']:
    expr_mean = grouped_obs_mean(adata, by)
    for k in set(df[df['by'] == by]['cluster']):
        plt.subplot(5, 5, pi + 1)
        grp = df[(df['cluster'] == k) & (df['by'] == by)]
        grp['cluster.number'] = grp['archetype'].str.split('.').str[-1].astype(int)
        grp = grp.merge(motif, left_on='cluster.number', right_on='Cluster_ID')
        expr_by_gene = (expr_mean[k] - expr_mean.mean(axis=1)).to_dict()
        grp['gene.expr'] = grp['symbol'].map(expr_by_gene)
        grp = grp.drop_duplicates('symbol')
        # plt.scatter(grp['roc.auc'], grp['gene.expr'], s=5)
        plt.axhline(y=.0, ls='--')
        plt.axvline(x=.5, ls='--')

        grp['rank'] = pd.Series(np.sqrt(np.where(grp['gene.expr'] < 0, 0, grp['gene.expr']) *
                                        np.where(grp['roc.auc'] < 0.5, 0, grp['roc.auc'])).flatten(),
                                index=grp.index).rank(ascending=False)
        grp['color'] = np.where((grp['roc.auc'] > 0.5) & (grp['rank'] < 5), 'red', 'gray')
        # grp['color'] = np.where((grp['roc.auc'] > 0.5), 'red', 'gray')

        grp = grp[~np.isnan(grp['gene.expr'])]
        
        res.append(grp)
        
        # print(k, grp[~np.isnan(grp['gene.expr'])].shape[0], set(grp[~np.isnan(grp['gene.expr'])]['symbol']))
        plt.scatter(grp['roc.auc'], grp['gene.expr'], s=5, c=grp['color'])
        for ri, r in grp[(grp['color'] == 'red') | (grp['gene.expr'] > .5)].iterrows():
            plt.annotate(r['symbol'], (r['roc.auc'], r['gene.expr']), fontsize=10)
        plt.xlabel('ROC-AUC')
        plt.ylabel('expression')
        plt.ylim([-.25, 1.8])
        plt.xlim([.4, .9])
        plt.title('%s (%s)' % (k, by))
        pi += 1

res = pd.concat(res)


plt.subplots_adjust(bottom=.5, hspace=.8, wspace=.6) #  right=.6)
# plt.tight_layout()

sel_tfs = set(res[(res['color'] == 'red') | (res['gene.expr'] > .5)]['symbol'])
# print(sel_tfs)
sel_archetypes = motif[motif['symbol'].isin(sel_tfs)]

archetype_by_symbol = motif[motif['symbol'].isin(sel_tfs)].set_index('symbol')['Cluster_ID'].to_dict()

if False:
    res['color'] = np.where((res['roc.auc'] > 0.5) & (res['gene.expr'] > .25), 'red', 'gray')
    plt.scatter(res['roc.auc'], res['gene.expr'], s=5, c=res['color'])
    for ri, r in grp[grp['gene.expr'] > .5].iterrows():
        plt.annotate(r['symbol'], (r['roc.auc'], r['gene.expr']), fontsize=6)
    plt.xlabel('ROC-AUC')
    plt.ylabel('expression [mean]')
    plt.title('Expression versus reg. potential')
    
leiden
cell.type
In [323]:
sc.pl.umap(adata, color=['leiden', 'cell.type'], ncols=2)
In [430]:
res['k'] = res['by'] + '_' + res['cluster']
sel_df = res.sort_values(['rank', 'roc.auc'], ascending=[True, False]).groupby('k').head(5).sort_values(['k', 'rank'])
sel_tfs = set(sel_df['symbol'])
print(len(sel_tfs))
49

Plot expression of TFs whole archetype motifs have the highest activities

In [500]:
def plot_best_cases_umap(by='cell.type'):
    set_figsize(4, 4)
    set_figdpi(100)
    res['cluster.name'] = res['Cluster_ID'].map(name_by_cluster)
    for k in set(res['k']):
        if not by in k:
            continue
        cell_type_name = k.split('_')[1]
        adata.obs['is.%s' % cell_type_name] = adata.obs[by] == cell_type_name

        grp = res[res['k'] == k].sort_values(['rank', 'roc.auc'], ascending=[True, False]).groupby('k').head(5).sort_values('roc.auc', ascending=False)

        set_figdpi(60)
        sc.pl.umap(adata, color='is.%s' % cell_type_name, ncols=5, cmap='Set1_r', title=cell_type_name)

        set_figdpi(70)
        print('TF-expression')
        sc.pl.umap(adata, color=list(grp['symbol']), ncols=5, cmap='magma_r', title=grp['cluster.name'], vmin=0)
        print('regulatory potential')
        sc.pl.umap(adata, color=list(grp['archetype']), ncols=5, cmap='magma_r', title=k + '_' + grp['symbol'], vmin=0)
        
def plot_best_motifs(by='cell.type'):
    import matplotlib
    import seaborn as sns
    grp = sel_df[sel_df['by'] == by]
    best_with_expr = set(grp['archetype'])
    # print(best_3_per_case)

    sel = res[res['archetype'].isin(best_with_expr) & (res['by'] == by)]
    sel['k2'] = sel['cluster'] + sel['archetype']
    sel = sel.drop_duplicates('k2')
    sel['archetype.name'] = sel['Cluster_ID'].map(name_by_cluster)
    sel['archetype.TF'] = sel['archetype.name'] + ', (' + sel['symbol'] + ')'

    roc_hm = sel.pivot('cluster', 'archetype.TF', 'roc.auc').transpose()
    # roc_hm.index = roc_hm.index.str.split('.').str[-1].astype(int).map(name_by_cluster) + ', (' + roc_hm.index.str.split('.').str[-1].astype(str) + ')'

    fg = sns.clustermap(roc_hm, vmin=.5, vmax=.9, cmap='Blues') # yticklabels=False)
    plt.subplots_adjust(bottom=.5, left=.4)
    fg.gs.update(left=0.05, right=0.3)
    plt.setp(fg.ax_heatmap.get_xticklabels(), rotation=90, fontsize=7)

    #create new gridspec for the right part
    gs2 = matplotlib.gridspec.GridSpec(1, 1, left=0.6, top=.6)
    # create axes within this new gridspec
    ax2 = fg.fig.add_subplot(gs2[0])

    plot_motifs_rows_clustermap(roc_hm.index[fg.dendrogram_row.reordered_ind])
In [504]:
plot_best_motifs(by='cell.type')
In [503]:
plot_best_cases_umap(by='cell.type')
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
In [502]:
plot_best_motifs(by='leiden')
In [501]:
plot_best_cases_umap(by='leiden')
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential
TF-expression
regulatory potential